﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core;

namespace Cofe.Data
{
    //Most taken from Programming EntityFramework: DbContext
    public static class DbContextUtils
    {
        //public static EntityState ConvertState(EntryState state)
        //{
        //    switch (state)
        //    {
        //        case EntryState.Modified :
        //            return EntityState.Modified;
        //        case EntryState.Added:
        //            return EntityState.Added;
        //        case EntryState.Deleted:
        //            return EntityState.Deleted;
        //        default:
        //            return EntityState.Unchanged;
        //    }
        //}

        //public static void CheckForEntitiesWithoutStateInterface(DbContext context)
        //{
        //    var entitiesWithoutState = from e in context.ChangeTracker.Entries()
        //                               where !(e.Entity is IObjectWithState)
        //                               select e;

        //    if (entitiesWithoutState.Any())
        //    {
        //        throw new NotSupportedException("All entities must implement IObjectWithState");
        //    }
        //}

        //public static void ApplyChanges<TEntity>(Func<DbContext> contextFunc, TEntity root)
        //    where TEntity : class, IObjectWithState
        //{
        //    using (var context = contextFunc())
        //    {
        //        context.Set<TEntity>().Add(root);
        //        DbContextUtils.CheckForEntitiesWithoutStateInterface(context);

        //        foreach (var entry in context.ChangeTracker.Entries<IObjectWithState>())
        //        {
        //            IObjectWithState stateInfo = entry.Entity;
        //            entry.State = DbContextUtils.ConvertState(stateInfo.EntryState);
        //            if (stateInfo.EntryState == EntryState.Unchanged)
        //            {
        //                var databaseValues = entry.GetDatabaseValues();
        //                entry.OriginalValues.SetValues(databaseValues);
        //            }
        //        }

        //        context.SaveChanges();
        //    }
        //}

        private static void ApplyPropertyChanges(DbPropertyValues values, Dictionary<string, object> originalValues)
        {
            foreach (var originalValue in originalValues)
            {
                if (originalValue.Value is Dictionary<string, object>)
                {
                    ApplyPropertyChanges(
                    (DbPropertyValues)values[originalValue.Key],
                    (Dictionary<string, object>)originalValue.Value);
                }
                else
                {
                    values[originalValue.Key] = originalValue.Value;
                }
            }
        }


        public static void PrintChangeTrackingInfo(DbContext context, object entity)
        {
            var entry = context.Entry(entity);

            Console.WriteLine("Type: {0}", entry.Entity.GetType());

            Console.WriteLine("State: {0}", entry.State);

            if (entry.State != EntityState.Deleted)
            {
                Console.WriteLine("\nCurrent Values:");
                PrintPropertyValues(entry.CurrentValues);
            }

            if (entry.State != EntityState.Added)
            {
                Console.WriteLine("\nOriginal Values:");
                PrintPropertyValues(entry.OriginalValues);

                Console.WriteLine("\nDatabase Values:");
                PrintPropertyValues(entry.GetDatabaseValues());
            }
        }

        public static void PrintPropertyValues(DbPropertyValues values, int indent = 1)
        {
            foreach (var propertyName in values.PropertyNames)
            {
                var value = values[propertyName];
                if (value is DbPropertyValues)
                {
                    Console.WriteLine(
                      "{0}- Complex Property: {1}",
                      string.Empty.PadLeft(indent),
                      propertyName);

                    PrintPropertyValues(
                      (DbPropertyValues)value,
                      indent + 1);
                }
                else
                {
                    Console.WriteLine(
                      "{0}- {1}: {2}",
                      string.Empty.PadLeft(indent),
                      propertyName,
                      values[propertyName]);
                }
            }
        }

    }
}
